//我们假设properties，不可为空，三个参数必填
//我们假设tagname仅包含标签名
import {VNode} from './vnode';
import {VText} from './vtext'
export function h(tagName:string,properties:any,children:any[]) {
    let childNodes=[];
    let tag:string,props:any,namespace,key;
    props=props||properties||{}; 
    tag=tagName.toLowerCase();
     if (props.hasOwnProperty('key')) {
        key = props.key;
        props.key = undefined;
    }
    if (props.hasOwnProperty("namespace")) {
        namespace=props.namespace;
        props.namespace=undefined;
    }
    if (tag==='INPUT'&&
        props.hasOwnProperty('value')&&
        props.value!=undefined
    ) {
        if (props.value!=null&&typeof props.value!=='string') {
            throw UnsupportedValueType({
                expected:"string",
                received:typeof props.value,
                Vnode:{
                    tagName:tag,
                    properties:props
                }
            });
        }
    }
    if (children!==undefined&&children!=null&&children.length>0) {
        addChild(children, childNodes, tag, props);
    }
     return new VNode(tag, props, childNodes, key, namespace);
}

function addChild(curChildren,childNodes:any[],tag:string,props:any){
    if (typeof curChildren==='string') {
        childNodes.push(new VText(curChildren));
    }else if (typeof curChildren==='number') {
        childNodes.push(new VText(curChildren+""));
    }else if (isChild(curChildren)) {
        childNodes.push(curChildren);
    }else if(isArray(curChildren)){
        curChildren.forEach(element => {
            addChild(element,childNodes,tag,props);
        });
    }
    else if (curChildren==null||curChildren==null) {
        return;
    }else{
        throw UnsupportedValueType({
            foreignObject:curChildren,
            parentVnode:{
                tagName:tag,
                properties:props
            }
        });
    }
}

function isChild(x) {
    return x.type==='VirtualNode'|| x.type==='VirtualText';
}

function isArray(ss){
    return Object.prototype.toString.call(ss) === '[object Array]'&&ss.length>0;
}

function UnexpectedVirtualElement(data) {
    var err = new Error();
    
   ( err as any).type = 'virtual-hyperscript.unexpected.virtual-element';
    err.message = 'Unexpected virtual child passed to h().\n' +
        'Expected a VNode / Vthunk / VWidget / string but:\n' +
        'got:\n' +
        errorString(data.foreignObject) +
        '.\n' +
        'The parent vnode is:\n' +
        errorString(data.parentVnode)
        '\n' +
        'Suggested fix: change your `h(..., [ ... ])` callsite.';
     ( err as any).foreignObject = data.foreignObject;
     ( err as any).parentVnode = data.parentVnode;

    return err;
}



function UnsupportedValueType(data) {
    var err = new Error();

     ( err as any).type = 'virtual-hyperscript.unsupported.value-type';
    err.message = 'Unexpected value type for input passed to h().\n' +
        'Expected a ' +
        errorString(data.expected) +
        ' but got:\n' +
        errorString(data.received) +
        '.\n' +
        'The vnode is:\n' +
        errorString(data.Vnode)
        '\n' +
        'Suggested fix: Cast the value passed to h() to a string using String(value).';
    ( err as any).Vnode = data.Vnode;

    return err;
}

function errorString(obj) {
    try {
        return JSON.stringify(obj, null, '    ');
    } catch (e) {
        return String(obj);
    }
}